#include <mFS/FsTypes.h>
#include <mFS/mConfig.h>
#include <Utils/Mem.h>
#include <Utils/StructDef.h>
#include <apdu/APDUParse.h>
#include <apdu/SwCode.h>
#include <apdu/CryptSymCipherAP.h>
#include <cmd/CMDCryptSymCipher.h>


static UINT16 CMDCryptSymCipher_CipherInit(UINT8 Mode)
{
	ApduCmd *pCmd;
	UINT16 nRet;

	pCmd = APDU_GetCmd();

	if(pCmd->CLA != 0x80)
	{
		return (ISOSW_CLA_ERROR);
	}

	if(pCmd->LC < sizeof(CipherHeader) + 4 + 4)
	{
		return (ISOSW_LC_ERROR);
	}

	if(pCmd->P1 != 0 || pCmd->P2 != 0)
	{
		return (ISOSW_P1P2_ERROR);
	}

	nRet = CryptSymCipherAP_CipherInit(Mode, pCmd->pData, pCmd->LC);

	return (nRet);
}

static UINT16 CMDCryptSymCipher_Cipher(UINT8 Mode, UINT16 *pLen)
{
	ApduCmd *pCmd;
	ApduRsp *pRsp;
	UINT16 nRet;

	pCmd = APDU_GetCmd();
	pRsp= APDU_GetRsp();

	if(pCmd->CLA != 0x80)
	{
		return (ISOSW_CLA_ERROR);
	}

	if(pCmd->LC < 2 + 2 + 2)
	{
		return (ISOSW_LC_ERROR);
	}

	if(pCmd->P1 != 0 || pCmd->P2 != 0)
	{
		return (ISOSW_P1P2_ERROR);
	}

	nRet = CryptSymCipherAP_Cipher(Mode, pCmd->pData, pCmd->LC, pRsp->pData, pLen);

	return (nRet);
}

static UINT16 CMDCryptSymCipher_CipherUpdate(UINT8 Mode, UINT16 *pLen)
{
	ApduCmd *pCmd;
	ApduRsp *pRsp;
	UINT16 nRet;

	pCmd = APDU_GetCmd();
	pRsp= APDU_GetRsp();

	if(pCmd->CLA != 0x80)
	{
		return (ISOSW_CLA_ERROR);
	}

	if(pCmd->LC < 2 + 2 + 2)
	{
		return (ISOSW_LC_ERROR);
	}

	if(pCmd->P1 != 0 || pCmd->P2 != 0)
	{
		return (ISOSW_P1P2_ERROR);
	}

	nRet = CryptSymCipherAP_CipherUpdate(FALSE, Mode, pCmd->pData, pCmd->LC, pRsp->pData, pLen);

	return (nRet);
}

static UINT16 CMDCryptSymCipher_CipherFinal(UINT8 Mode, UINT16 *pLen)
{
	ApduCmd *pCmd;
	ApduRsp *pRsp;
	UINT16 nRet;

	pCmd = APDU_GetCmd();
	pRsp= APDU_GetRsp();

	if(pCmd->CLA != 0x80)
	{
		return (ISOSW_CLA_ERROR);
	}

	if(pCmd->LC < 2 + 2 + 2)
	{
		return (ISOSW_LC_ERROR);
	}

	if(pCmd->P1 != 0 || pCmd->P2 != 0)
	{
		return (ISOSW_P1P2_ERROR);
	}

	nRet = CryptSymCipherAP_CipherFinal(Mode, pCmd->pData, pCmd->LC, pRsp->pData, pLen);

	return (nRet);
}

void CMDCryptSymCipher_EncryptInit(void)
{
	UINT16 nRet;

	nRet = CMDCryptSymCipher_CipherInit(CRYPTSYMCIPHERAP_MODE_ENCRYPT);

	APDU_SetRespond(0, nRet);

	return ;
}

void CMDCryptSymCipher_Encrypt(void)
{
	UINT16 nRet;
	UINT16 Len;

	nRet = CMDCryptSymCipher_Cipher(CRYPTSYMCIPHERAP_MODE_ENCRYPT, &Len);

	APDU_SetRespond(Len, nRet);

	return ;
}

void CMDCryptSymCipher_EncryptUpdate(void)
{
	UINT16 nRet;
	UINT16 Len;

	nRet = CMDCryptSymCipher_CipherUpdate(CRYPTSYMCIPHERAP_MODE_ENCRYPT, &Len);

	APDU_SetRespond(Len, nRet);

	return ;
}

void CMDCryptSymCipher_EncryptFinal(void)
{
	UINT16 nRet;
	UINT16 Len;

	nRet = CMDCryptSymCipher_CipherFinal(CRYPTSYMCIPHERAP_MODE_ENCRYPT, &Len);

	APDU_SetRespond(Len, nRet);

	return ;
}

void CMDCryptSymCipher_DecryptInit(void)
{
	UINT16 nRet;

	nRet = CMDCryptSymCipher_CipherInit(CRYPTSYMCIPHERAP_MODE_DECRYPT);

	APDU_SetRespond(0, nRet);

	return ;
}

void CMDCryptSymCipher_Decrypt(void)
{
	UINT16 nRet;
	UINT16 Len;

	nRet = CMDCryptSymCipher_Cipher(CRYPTSYMCIPHERAP_MODE_DECRYPT, &Len);

	APDU_SetRespond(Len, nRet);

	return ;
}

void CMDCryptSymCipher_DecryptUpdate(void)
{
	UINT16 nRet;
	UINT16 Len;

	nRet = CMDCryptSymCipher_CipherUpdate(CRYPTSYMCIPHERAP_MODE_DECRYPT, &Len);

	APDU_SetRespond(Len, nRet);

	return ;
}

void CMDCryptSymCipher_DecryptFinal(void)
{
	UINT16 nRet;
	UINT16 Len;

	nRet = CMDCryptSymCipher_CipherFinal(CRYPTSYMCIPHERAP_MODE_DECRYPT, &Len);

	APDU_SetRespond(Len, nRet);

	return ;
}
